package dml.users.proc;

import dml.users.aggr.*;
import dml.users.repo.SessionRepository;
import dml.users.repo.UserBanFactoryRepository;
import dml.users.repo.UserBanRepository;
import dml.users.repo.UserLoginStateRepository;

public class UserBanProcesses {

    private UserBanRepository<UserBan, Object> userBanRepository;

    private UserLoginStateRepository<UserLoginState, Object> userLoginStateRepository;

    private SessionRepository<Session> sessionRepository;

    private UserBanFactoryRepository<UserBanFactory<UserBan, UserBanProperties>> userBanFactoryRepository;

    public UserBanProcesses(UserBanRepository<?, ?> userBanRepository,
                            UserLoginStateRepository<?, ?> userLoginStateRepository,
                            SessionRepository<?> sessionRepository,
                            UserBanFactoryRepository<?> userBanFactoryRepository) {
        this.userBanRepository = (UserBanRepository<UserBan, Object>) userBanRepository;
        this.userLoginStateRepository = (UserLoginStateRepository<UserLoginState, Object>) userLoginStateRepository;
        this.sessionRepository = (SessionRepository<Session>) sessionRepository;
        this.userBanFactoryRepository = (UserBanFactoryRepository<UserBanFactory<UserBan, UserBanProperties>>) userBanFactoryRepository;
    }

    public <UB extends UserBan> UB checkBanAndTryToReleaseUserOrLogout(
            Object userId, long currTime) {
        UserBan userBan = userBanRepository.take(userId);
        if (userBan == null) {
            return null;
        }
        Ban ban = userBan.getBan();
        if (ban == null) {
            return null;
        }
        if (ban.isReleased()) {
            return (UB) userBan;
        }
        boolean released = ban.toRelease(currTime);
        if (!released) {
            UserLoginState userLoginState = userLoginStateRepository.find(userId);
            sessionRepository.remove(userLoginState
                    .getSessionId());
            userLoginStateRepository.remove(userId);
        } else {
            userBanRepository.remove(userId);
        }
        return (UB) userBan;
    }

    public <UB extends UserBan> UB banUser(Object userId, long currTime,
                                           long liftTime, UserBanProperties userBanProperties) {
        if (liftTime < currTime) {
            return null;
        }
        UserBanFactory<UserBan, UserBanProperties> userBanFactory = userBanFactoryRepository.get();
        UserBan userBan = userBanFactory.create(userBanProperties);
        userBan.setId(userId);
        userBan.setBan(new Ban(currTime, liftTime));
        UserBan existsBan = userBanRepository.putIfAbsent(userBan);
        if (existsBan != null) {
            return null;
        }
        UserLoginState userLoginState = userLoginStateRepository
                .remove(userId);
        sessionRepository.remove(userLoginState.getSessionId());
        return (UB) userBan;
    }

    public <UB extends UserBan> UB liftUserBan(Object userId, long currTime) {
        return (UB) userBanRepository.remove(userId);
    }

}
